<?php

namespace app\socket;

use app\model\iot_model\IotDevice;
use Swoole\WebSocket\Frame;
use think\swoole\Websocket;

/**
 * WebSocket
 */
class Server
{
    /**
     * 连接ws连接
     * @return \think\swoole\response\Websocket
     */
    public function onOpen(): \think\swoole\response\Websocket
    {
        // 通过 websocket() 助手函数注册事件回调
        return \think\swoole\helper\websocket()
            // 连接建立事件
            ->onOpen(function (Websocket $websocket, $request) {
//                $param = $request->param(); // 获取用户ID
//                if (!empty($param['uid'])){
//                    $fd = $websocket->getSender(); // 当前连接的fd
//                    $lock = 'wsUserId_'.$param['uid'];
//                    $fdLock = 'wsFd'.$fd;
//                    // 用一个全局数组或缓存（如Redis）存储用户ID与fd的映射
//                    cache($lock,$fd);
//                    cache($fdLock,$lock);
//                }
                $websocket->join('all');
            })
            ->onMessage(function (Websocket $websocket, Frame $frame) {
                $data = json_decode($frame->data, true); // 解析前端发送的JSON
                switch ($data['ws_type'] ?? '') {
                    case 'bind':
                        //绑定用户
                        $fd = $websocket->getSender(); // 当前连接的fd
                        $lock = 'wsUserId_' . $data['from_uid'] ?? '';
                        $fdLock = 'wsFd' . $fd;
                        cache($lock, $fd, 120);
                        cache($fdLock, $lock, 120);
                        break;
                    case 'send':
                        //发送消息
                        $lock = 'wsUserId_' . $data['to_uid'] ?? '';
                        $fd = cache($lock);
                        $websocket->to([$fd])->push(json_encode($data['content']));
                        break;
                    case 'getToken':
                        //获取二维码token
                        $token = md5(time() . uniqid());
                        $websocket->push(json_encode([
                            'type' => 'token',
                            'type_name' => '获取token',
                            'content' => $token
                        ]));
                        break;
                    case 'onlineStatus':
                        //在线状态
                        if (!empty($data['consult_id'])) {
                            foreach ($data['consult_id'] as $k => $v) {
                                if (!cache('wsUserId_' . $v)) {
                                    unset($data['consult_id'][$k]);
                                }
                            }
                            $websocket->to([$websocket->getSender()])->push(json_encode([
                                'type' => 'onlineStatus',
                                'content' => $data['consult_id']
                            ]));
                        }
                        break;
                    case 'iot':
                        //物联
                        $IotDeviceModel = new IotDevice();
                        $info = $IotDeviceModel->field('id,is_online,end_synchronous_time')->where('mac','=',$data['content'])->find();
                        if ($info) {
                            cache($websocket->getSender().'mac',$info['id'],60);
                            if($info['is_online'] == 0){
                                //如果已经同步过了就不用再记录【记录第一次同步的时间】
                                $update = [
                                    'is_online'=>1,
                                    'update_time'=>time(),
                                    'end_synchronous_time'=>time(),
                                ];
                                if($info['end_synchronous_time'] == 0){
                                    $update['first_synchronous_time'] = time();
                                }
                                $info->save($update);
                            }
                            $websocket->push($websocket->getSender().'成功！');
                        }else{
                            $websocket->push($websocket->getSender().'同步失败，mac地址不存！请重新填写mac地址！');
                        }
                        break;
                    case 'setKey':
                        $key = $data['content'];
                        if (!empty($key) && $key == env('JMG_KEY') && env('JMG_STATUS')){
                            cache(env('REDIS_PROJECT').'jmg_key',$key,1);
                        }else{
                            if (cache(env('REDIS_PROJECT').'jmg_key') != env('JMG_KEY') && env('JMG_STATUS')){
                                $websocket->to('all')->push(json_encode([
                                    'type' => 'setKey',
                                    'content' => error('请插入加密狗！')
                                ]));
                                break;
                            }
                        }
                        $websocket->to('all')->push(json_encode([
                            'type' => 'setKey',
                            'content' => success(env('JMG_STATUS'))
                        ]));
                        break;
                }
            })
            ->onClose(function (Websocket $websocket) {
                $fdLock = 'wsFd' . $websocket->getSender();
                $lock = cache($fdLock);
                if ($lock) {
                    cache($lock, null);
                    cache($fdLock, null);
                }

                //物联
                $mac = cache($websocket->getSender().'mac');
                if($mac){
                    $update = [
                        'is_online'=>0,
                        'update_time'=>time(),
                    ];
                    $IotDeviceModel = new IotDevice();
                    $IotDeviceModel->where('id','=',$mac)->update($update);
                }
            });
    }

    /**
     * 通过用户id获取fd
     * @param array $uid
     * @return array
     */
    public function uidGetFd(array $uid): array
    {
        $fds = [];
        foreach ($uid as $v) {
            $fd = cache('wsUserId_' . $v);
            if (!empty($fd)) {
                $fds[] = $fd;
            }
        }
        return $fds;
    }

    /**
     * 推送消息
     * @param array $fd
     * @param string $data
     * @param Websocket $websocket
     * @return void
     */
    public function push(array $fd, string $data, Websocket $websocket): void
    {
        if (!empty($fd)) {
            $websocket->to($fd)->push($data);
        }
    }
}